#include "linuxinputtype.h"
#include <iostream>

extern "C"
{
  #include <fcntl.h>
  #include <errno.h>
  #include <sys/ioctl.h>
  #include <linux/joystick.h>
}

LinuxInputType::LinuxInputType()
  : mFD(0)
{
  open();
}

LinuxInputType::~LinuxInputType()
{
  close();
}

bool LinuxInputType::poll()
{
  bool ret(false);

  if (isOpen())
  {
    ret = true;
    js_event e;
    if (read(&e, sizeof(js_event)))
    {
      switch(e.type & ~JS_EVENT_INIT)
      {
      case  JS_EVENT_BUTTON:
        mData.setButton(e.number, e.value);
        break;
      case JS_EVENT_AXIS:
        mData.setAxis(e.number, e.value);
        break;
      default:
        break;
      }
    }
  }

  return ret;
}

bool LinuxInputType::isOpen() const
{
  return mFD > 0;
}

void LinuxInputType::open()
{
  int openFlags(O_RDWR | O_NONBLOCK);
  mFD = ::open("/dev/js0", openFlags);
  if (!isOpen())
  {
    mFD = ::open("/dev/input/js0", openFlags);
    if (isOpen())
    {
      char name[80];
      ioctl(mFD, JSIOCGNAME(sizeof(name)), &name);
      mName = name;
      int numAxes(0), numButtons(0);
      ioctl(mFD, JSIOCGAXES, &numAxes);
      ioctl(mFD, JSIOCGBUTTONS, &numButtons);
      mData.setNumAxes(numAxes);
      mData.setNumButtons(numButtons);
    }
  }
  if (!isOpen())
  {
    std::cout << "LinuxInputType cannot find js0" << std::endl;
  }
}

void LinuxInputType::close()
{
  if (isOpen())
  {
    ::close(mFD);
    mFD = 0;
    mData.reset();
  }
}

bool LinuxInputType::read(void *data, unsigned int bytes)
{
  bool ret(false);

  if (isOpen())
  {
    ssize_t bytesRead(::read(mFD, data, bytes));
    if (bytesRead == static_cast<ssize_t>(bytes))
    {
      ret = true;
    }
    else if (errno == EAGAIN)
    {
      //no data to read currently
    }
    else
    {
      std::cout << "LinuxInputType read error: " << errno
                << std::endl;
    }
  }

  return ret;
}
